#include <iostream>
#include <sstream>

#include "node.h"
#include "sudo.h"
#include "sudokuLoader.h"

using namespace std;

int getNode( int x, int y, int nx, int ny ) {
	return (x * nx) + ny;
}


int main ( int argc, char * argv[] ) {

	srand( time(NULL) );

	vector<node> nodes;
	vector<sudo> sudoh;
	vector<sudo> sudov;
	vector<sudo> sudob;

	int x = 9;
	int y = 9;

	int nodeboxes = 9;

	int nodeb_x = 3;
	int nodeb_y = 3;

	int hypos = 9;

	long delay = 100000;
	bool pause = false;

	bool color = false;
	int colortmp = 0;

	bool errors = false;
	bool pretty = false;

	bool loop;
	bool action;
	bool test = true;	
	int iter_count = 0;

	int node_count = x * y;

	stringstream buf;

	for ( int i = 1; i < argc; ++i ) {
		buf.str("");
		buf << argv[i];
		if ( buf.str() == "--pause" ) {
			pause = true;
		}
		if ( buf.str() == "--nopause" ) {
			pause = false;
		}
		if ( buf.str() == "--color" ) {
			color = true;
		}
		if ( buf.str() == "--nocolor" ) {
			color = false;
		}
		if ( buf.str() == "--pretty" ) {
			pretty = true;
		}
		if ( buf.str() == "--ugly" ) {
			pretty = false;
		}
		if ( buf.str() == "--errors" ) {
			errors = true;
		}
		if ( buf.str() == "--noerrors" ) {
			errors = false;
		}
		if ( buf.str() == "--load" ) {
			// load Sudoku Grid?
		}
	}

	sudo temp;

	sudokuLoader loader("default.sudo");

	for ( int i = 0; i < x; ++i ) {
		sudoh.push_back( temp );
	}
	for ( int i = 0; i < y; ++i ) {
		sudov.push_back( temp );
	}
	for ( int i = 0; i < nodeboxes; ++i ) {
		sudob.push_back( temp );
	}

if ( loader.isReady() ) {
	for ( int i = 0; i < x; ++i ) {
		nodes = loader.getGrid();
	}
} else {
if ( errors ) {
	cout << "Failure! Loading Default Grid!\n";
	usleep(2000000);
}
	for ( int i = 0; i < node_count; ++i ) {
		node temp_node( hypos ); // ID, Hypo Count
		nodes.push_back( temp_node );
	}
}
	for ( int ix = 0; ix < x; ++ix ) {
		for ( int iy = 0; iy < y; ++iy ) {
			nodes[getNode( x, y, ix, iy )].setStatus( 0 );
			sudoh[ix].addNode( &nodes[getNode( x, y, ix, iy )] );
			sudov[iy].addNode( &nodes[getNode( x, y, ix, iy )] );
		}
	}

	int boxx = nodeboxes / nodeb_x;
	int boxy = nodeboxes / nodeb_y;

	int count = 0;
	int status;
	int best;
	int tmp;

	for ( int ix = 0; ix < x; ix = ix + boxx ) {
		for ( int iy = 0; iy < y; iy = iy + boxy ) {
			for ( int i = ix; i < ix + boxx; ++i ) {
				for ( int n = iy; n < iy + boxy; ++ n ) {
//					cout << i << ", " << n << " ";
					sudob[count].addNode( &nodes[getNode( x, y, i, n )] );
				}
			}
			++count;
//			cout << "\n";
		}
	}

	for ( int i = 0; i < sudoh.size(); ++i ) {
		temp = sudoh[i];
		temp.connectNodes();
	}

	for ( int i = 0; i < sudov.size(); ++i ) {
		temp = sudov[i];
		temp.connectNodes();

	}

	for ( int i = 0; i < sudob.size(); ++i ) {
		temp = sudob[i];
		temp.connectNodes();

	}

	
	loop = true;

	while ( loop ) {

		for ( int ix = 0; ix < x; ++ix ) {
			for ( int iy = 0; iy < y; ++iy ) {
				nodes[getNode( x, y, ix, iy )].resetRate();
			}
		}

		for ( int ix = 0; ix < x; ++ix ) {
			for ( int iy = 0; iy < y; ++iy ) {
				nodes[getNode( x, y, ix, iy )].rateNodes();
			}
		}

		stringstream foo; 

		action = false;

		for ( int ix = 0; ix < x; ++ix ) {
			for ( int iy = 0; iy < y; ++iy ) {
				colortmp = nodes[getNode( x, y, ix, iy )].getStatus();
if ( color ) {
	if ( colortmp == 0 ) { foo << "[31m"; }
	if ( colortmp == 1 ) { foo << "[32m"; }
	if ( colortmp == 2 ) { foo << "[33m"; }
	if ( colortmp == 3 ) { foo << "[34m"; }
	if ( colortmp == 4 ) { foo << "[35m"; }
	if ( colortmp == 5 ) { foo << "[36m"; }
	if ( colortmp == 6 ) { foo << "[37m"; }
	if ( colortmp == 7 ) { foo << "[38m"; }
	if ( colortmp == 8 ) { foo << "[39m"; }
	if ( colortmp == 9 ) { foo << "[40m"; }
}
				foo << colortmp; 
if ( color ) {
	foo << "[0m";
}
				status = nodes[getNode( x, y, ix, iy )].getStatus();
				best = nodes[getNode( x, y, ix, iy )].getBestStatus();

				if ( status != best ) {
					if ( nodes[getNode( x, y, ix, iy )].isLocked() ) {
						if ( errors ) {
							cout << "changing a locked node\n";
						}
					} else {
						nodes[getNode( x, y, ix, iy )].setStatus( best );
						nodes[getNode( x, y, ix, iy)].rerateThings();
						action = true;
					}
				}
				foo << " ";
if ( pretty ) {
			if ( ( iy % boxy ) == 2 ) { foo << " "; }
}
			}
			foo << "\n";
if ( pretty ) {
			if ( ( ix % boxx ) == 2 ) { foo << "\n"; }
}
		}

if ( pause ) {	
		usleep( delay );
}

		cout << foo.str(); 
		cout << "\n"; 
	
		if ( ! action ) {
			test = true;
			for ( int ix = 0; ix < x; ++ix ) {
				for ( int iy = 0; iy < y; ++iy ) {
					if ( ! nodes[getNode(x, y, ix, iy )].strictCheck() ) {
//						nodes[getNode(x, y, ix, iy )].setStatus( rand() % nodes[getNode(x, y, ix, iy )].getHypoCount() );
						nodes[getNode(x, y, ix, iy )].setStatus( 1 );
						test = false;
					}
				}
			}
			if ( test ) {
				loop = false;
			}
		}
		++iter_count;
	}


if ( pretty ) {
	cout << "Solved: " << iter_count << " ( Iterations )\n\n";
}

	for ( int ix = 0; ix < x; ++ix ) {
		for ( int iy = 0; iy < y; ++iy ) {
			colortmp = nodes[getNode( x, y, ix, iy )].getStatus();
if ( color ) {
	if ( colortmp == 0 ) { cout << "[31m"; }
	if ( colortmp == 1 ) { cout << "[32m"; }
	if ( colortmp == 2 ) { cout << "[33m"; }
	if ( colortmp == 3 ) { cout << "[34m"; }
	if ( colortmp == 4 ) { cout << "[35m"; }
	if ( colortmp == 5 ) { cout << "[36m"; }
	if ( colortmp == 6 ) { cout << "[37m"; }
	if ( colortmp == 7 ) { cout << "[38m"; }
	if ( colortmp == 8 ) { cout << "[39m"; }
	if ( colortmp == 9 ) { cout << "[40m"; }
}
				cout << colortmp + 1 << " ";
if ( color ) {
	cout << "[0m";
}
if ( pretty ) {
		if ( ( iy % boxy ) == 2 ) { cout << " "; }
}
		}
		cout << "\n";
if ( pretty ) {
		if ( ( ix % boxx ) == 2 ) { cout << "\n"; }
}
	}

}

